#ifndef NEWGRIDCONNECTIONMANAGER_H
#define NEWGRIDCONNECTIONMANAGER_H

/*!
 * \file NewGridConnectionManager.h
 * \author thomas raynal
 * \version 2.0
 */

#include <set>
#include "GridTcpConnection.h"
#include "Log.h"
#include <string>

/*! \namespace Network
 * 
 * Group client/server related classes. Offer API for handling both server and clients.
 */
namespace Network
{
  /*! \class NewGridConnectionManager
   * \brief Handle new connections.
   * Handle subscription of new connections, use of referenced connections and connections availaibility.
   * Request & response message model must be specified
   */
template <class MessageRequest, class MessageResponse>
    class NewGridConnectionManager
    {
    public:
		 
		NewGridConnectionManager(){
		size_=0;
		sent_tasked = new std::map<std::string,std::string>();
		}

	/*!
    *  \brief Reference a connection
    *
    */
      void Start(boost::shared_ptr<GridTcpConnection<MessageRequest,MessageResponse>> c)
	  {
		  connections_.insert(c);
		  size_++;
		  c.get()->Start();
      }
      
	/*!
    *  \brief Kill a connection
    *
    */
      void Stop(boost::shared_ptr<GridTcpConnection<MessageRequest,MessageResponse>> c)
	  {
		  connections_.erase(c);
		  size_--;
		  c.get()->Stop();
	  }

	/*!
    *  \brief Keep a record of executed tasks
    *
    */
	  void UpdateSentTaskList(std::string task_id)
	  {

		  if (sent_tasked->size()>0)
		  {
			  std::map<std::string,std::string>::iterator pair_= sent_tasked->find(task_id);
			  string id;

		  		  for (std::set<boost::shared_ptr<GridTcpConnection<MessageRequest,MessageResponse>>>::iterator connections = connections_.begin(); connections != connections_.end(); connections++)
					{
						if (*((*connections)->GetName())==pair_->second)
						{
							(*connections)->SendTaskSent(false);
							sent_tasked->erase(pair_->first);
							break;
						}
					}
		  }
	  }

	/*!
    *  \brief Send a task to the first available client
    *
    */
	  void ExecuteTask (MessageRequest* msg, std::string* request_id)
	  {
		  bool sent_=false;
		  int active_connections = size_;

		  while (!sent_)
		  {
			  std::set<boost::shared_ptr<GridTcpConnection<MessageRequest,MessageResponse>>>::iterator connections =connections_.begin();

		     for (connections; connections != connections_.end(); connections++)
				{
					
					if (active_connections!=size_)
						{
							active_connections = size_;
								break;
						}
					else
					{
						if (!(*connections)->IsTaskSent())
							{
								MessageRequest message = *msg;
								MessageRequest* message_ptr = new MessageRequest(message);
								boost::shared_ptr<GridTcpConnection<MessageRequest,MessageResponse>> connection = *connections;
								sent_tasked->insert(std::pair<std::string,std::string>(*request_id,*connection.get()->GetName()));
								sent_ =true;
								connection.get()->SendTaskSent(true);
								connection.get()->Write(message_ptr,GridTcpConnection<MessageRequest,MessageResponse>::MESSAGE_TYPE::REQUEST);
								std::cout<<"Request "<< *request_id <<" sent to "<< *(connection.get()->GetName()) <<std::endl;
								break;
					
							}
					}
				}
		  }
	  }
      
	/*!
    *  \brief Close all registered connections
    *
    */
      void StopAll()
	  {
		  std::for_each(connections_.begin(), connections_.end(),boost::bind(&GridTcpConnection<MessageRequest,MessageResponse>::Stop, _1));
		  connections_.clear();
	  }

      bool Check(boost::shared_ptr<GridTcpConnection<MessageRequest,MessageResponse>> c)
	  {
		  bool isConnectionKilled = false;
		  c.get()->CheckIsAlive();

		  if (!c.get()->IsActive())
		  {
			 Stop(c);
			 isConnectionKilled = true;
		  }

		  return isConnectionKilled;
	  }

	/*!
    *  \brief Check all available connections for timout
    *
    */
      void CheckAll()
	  {
		 
		  	for (std::set<boost::shared_ptr<GridTcpConnection<MessageRequest,MessageResponse>>>::iterator connections = connections_.begin(); connections != connections_.end(); connections++)
			{

				bool result= Check(*connections);

				if (result)
				{
					connections=connections_.begin();

					if (connections==connections_.end())
						break;
				}
			}
	  }

	/*!
    *  \brief Print the numberof available connections on stdout
    *
    */
	  void PrintAvailableConnections()
	  {
		 PrintLog("Available connections:");
		 PrintLog(size_);
	  }

	  ~NewGridConnectionManager()
	  {
		  StopAll();
	  }

    private:
	int size_;
      std::set<boost::shared_ptr<GridTcpConnection<MessageRequest,MessageResponse>>> connections_;
	  std::map<std::string,std::string>* sent_tasked;
    };
	}
#endif 